import sys
import logging
import paramiko
import lwui

assert (lwui.__version__ > '0.2.4')
from lwui.uibase import CUIWindow, mkmain, QMessageBox, QThread, pyqtSignal
from lwui.utils import lwutil

EXTRA_UI = (
    '@G@选择',
    (
        '主机',
        '@E@host@qingyun',
        '用户',
        '@E@user@ubuntu',
        '@LED@link_status@green@0',
        '@B@connect@连接(&C)',
        '@LED@status@green@0',
        '@LED@red_status@red@0',
        '@BAR@progress@0@150',
        '@C@auto_clean@自动清除(&A)@1',
        '@B@reset@:green:清除输出(&R)',
        None,
    ),
    None,
    '命令',
    '@E@cmd_gw@service chat status',
    '@B@test@测试(&T)',
    '@B@sudo_test@提权执行(&S)',
    '@B@service_status@查看服务状态(&V)',
    '@B@service_reset@重启服务(&P)',
    None,
    '@TABW@log@标准输出',
    ('@T@log', ),
    '@TABW@err@错误输出',
    ('@T@err', ),
)

NS = 'main'
ver = '0.1.1-20230711'


class AsyncExec(QThread):

    def __init__(self, parent, cmd, *kw, **kwargs):
        self.parent = parent
        self.cmd = cmd
        super().__init__(parent, *kw, **kwargs)

    def run(self):
        p, cmd_text = self.parent, self.cmd
        out, err = p.ssh_exec(cmd_text)
        if cmd_text.startswith('echo'):
            echo_cmd_text = ''.join(cmd_text.split('|')[1:])
        else:
            echo_cmd_text = cmd_text
        p.cmd_signal.emit(echo_cmd_text, out, err)


class MyDeploy(CUIWindow):
    cmd_signal = pyqtSignal(str, str, str)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.ssh = None
        self.logger = self.make_logger(
            f'remote-{lwutil.get_timestr(fmt="%Y-%m-%d")}.log',
            level=logging.INFO)
        self.cmd_signal.connect(self.update_exec_result)
        self.btnE_connect()

    def btnE_connect(self):
        ssh = paramiko.SSHClient()
        ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
        try:
            host = self.get_etext('host')
            user = self.get_etext('user')
            ssh.connect(host, username=user)
            self.ssh = ssh
            self.set_etext('link_status', '1')
            self.set_etext('progress', '100')
        except Exception as e:
            QMessageBox.warning(self, '连接失败', str(e))
            return

    def get_cmd(self, cmd):
        return cmd

    def btnE_test(self):
        self.exec_cmd(self.get_etext('cmd_gw'))

    def btnE_sudo_test(self):
        self.sudo_exec_cmd(self.get_etext('cmd_gw'))

    def btnE_reset(self):
        self.set_etext('log', '', 'log')
        self.set_etext('err', '', 'err')

    def exec_cmd(self, cmd, confirm=False, sync=False):
        if self.ssh is None:
            QMessageBox.warning(self, '错误', '请先连接')
            return
        cmd_text = self.get_cmd(cmd)
        if confirm:  # 如果需要确认，则增加确认框
            msgBox = QMessageBox(self)
            msgBox.setText("确定执行命令?")
            msgBox.setInformativeText(f">{cmd_text}")
            msgBox.setStandardButtons(QMessageBox.Yes | QMessageBox.No)
            if msgBox.exec_() == QMessageBox.No:
                return
        if self.get_etext('auto_clean') == '1':
            self.set_etext('log', '', 'log')
        # 输出提示
        self.get_elem('log', 'log').append(
            f'<font color="red">[{lwutil.get_timestr()}]开始执行: \r\n</font>')
        if cmd_text.startswith('echo'):
            echo_cmd_text = ''.join(cmd_text.split('|')[1:])
        else:
            echo_cmd_text = cmd_text
        self.get_elem('log', 'log').append(echo_cmd_text)
        self.logger.info(f'开始执行: {echo_cmd_text}')
        self.update_statusbar('正在执行...')
        self.set_etext('progress', '20')

        if sync:
            out, err = self.ssh_exec(cmd_text)
            self.update_exec_result(echo_cmd_text, out, err)
        else:
            self._thread = AsyncExec(self, cmd_text)
            self._thread.start()

    def sudo_exec_cmd(self, cmd, sync=True):
        self.exec_cmd(f'echo "Go1234wk" | sudo -S {cmd}', sync=sync)

    def ssh_exec(self, cmd_text):
        if self.ssh:
            _, out, err = self.ssh.exec_command(cmd_text)
            return out.read().decode('utf-8'), err.read().decode('utf-8')
        else:
            return '', ''

    def update_exec_result(self, cmd_text, out, err):
        p = self
        self.set_etext('progress', '100')
        ts_text = lwutil.get_timestr()
        self.logger.info(f'执行结果: {out}')
        # 输出执行结果
        p.get_elem('log', 'log').append(
            f"\r\n<font color=\"#FF0000\">[{ts_text}]执行结果: \r\n</font>")
        p.get_elem('log', 'log').append(out)
        # 输出错误信息
        if err:
            p.get_elem('err', 'err').append(
                f"\r\n<font color=\"#FF0000\">[{ts_text}]执行结果: \r\n</font>{err}"
            )
            p.set_etext('status', '0')
            p.set_etext('red_status', '1')
            p.update_statusbar(f"执行失败: {cmd_text}")
        else:
            p.set_etext('status', '1')
            p.set_etext('red_status', '0')
            p.update_statusbar(f"执行完成: {cmd_text}")

    def parse_ret(self, keys=['.service -', 'Active:']):
        text = self.get_etext('log', 'log')
        ret = ['---分析结果---']
        for line in text.splitlines():
            for key in keys:
                if key in line:
                    ret.append(line)
        self.get_elem('log', 'log').append('\n'.join(ret))

    def continus_sudo_exec(self, cmds, func=None, sync=False):
        auto_clean = self.get_etext('auto_clean')
        self.set_etext('auto_clean', '0')
        for cmd in cmds:
            self.sudo_exec_cmd(cmd)
        if func:
            func()
        self.set_etext('auto_clean', auto_clean)

    def btnE_service_status(self):
        self.continus_sudo_exec(
            ['service chat status', 'service clash status'],
            self.parse_ret,
            sync=True)

    def btnE_service_reset(self):
        self.continus_sudo_exec(
            ['service chat restart', 'service clash restart'])


if __name__ == '__main__':
    mkmain(MyDeploy, "Remote-{}".format(ver), EXTRA_UI)
